package com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.util.interceptor;

import java.sql.Connection;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;

import com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.util.interceptor.constants.ConstantsSQLModelUtil;
import com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.util.interceptor.constants.vo.SqlModelVO;
import com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.util.interceptor.util.ReflectUtil;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class DataAuthorityInterceptor implements Interceptor {

	private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
	private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
				DEFAULT_OBJECT_WRAPPER_FACTORY);
		MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");

		String _mappedStatementId = mappedStatement.getId();
		BoundSql boundSql = statementHandler.getBoundSql();

		String afterOperationSQL = afterOperationSQL(_mappedStatementId, boundSql.getSql());

		// 利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句
		// ReflectUtil.setFieldValue(boundSql, "sql", afterOperationSQL);

		return invocation.proceed();
	}

	/**
	 * 重新封装执行的SQL语句( 根据目前配置的权限规则，重新处理执行的SQL ，添加相关的入参形式)
	 * 
	 * @param inputMappedStatementId
	 *            整体执行的 SQL 语句的节点（包含 namespace + 节点名称） 形如：
	 *            com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.manager.demo
	 *            .upload.DemoAttachmentMapper.selectCountByMap
	 * @param inputSql
	 *            原执行的SQL 语句 形如： select count(*) from demo_attachment
	 *            demo_attachment
	 * @return 根据权限规则，重新封装此处需要执行的SQL 语句 形如 新增 （where demo_attachment.ID = ?）
	 */
	private String afterOperationSQL(String inputMappedStatementId, String inputSql) {

		StringBuffer _inputSqlStrBuffer = new StringBuffer(inputSql);

		// 命名空间 形如：
		// com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.manager.demo.upload.DemoAttachmentMapper
		String _namespaceStatementId = inputMappedStatementId.substring(0, inputMappedStatementId.lastIndexOf("."));
		// 执行的节点名称： 形如 ： selectCountByMap
		String _methodStatementId = inputMappedStatementId.substring(inputMappedStatementId.lastIndexOf(".") + 1,
				inputMappedStatementId.length());

		if (_methodStatementId.equals("selectCountByMap")) {
			if (inputSql.contains("where")) {
				_inputSqlStrBuffer.append(" and ");
			} else {
				_inputSqlStrBuffer.append(" where ");
			}
			_inputSqlStrBuffer.append(deployOperationCountSQL(_namespaceStatementId));
		}
		
		if (_methodStatementId.equals("selectListByMap")) {
			_inputSqlStrBuffer = deployOperationListSQL(_namespaceStatementId, _inputSqlStrBuffer);
		}

		return _inputSqlStrBuffer.toString();
	}

	/**
	 * 从 配置的权限项中取出相关的配置项并生成相关的SQL
	 * 
	 * @param inputNamespaceStatementId
	 *            命名空间 形如：
	 *            com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.manager.demo
	 *            .upload.DemoAttachmentMapper
	 * @return
	 */
	private StringBuffer deployOperationCountSQL(String inputNamespaceStatementId) {
		StringBuffer _strBuffer = new StringBuffer();
		List<SqlModelVO> sqlModelVOList = ConstantsSQLModelUtil.operationMap.get(inputNamespaceStatementId);
		if (sqlModelVOList != null && sqlModelVOList.size() > 0) {
			for (SqlModelVO sqlModelVO : sqlModelVOList) {
				_strBuffer
						.append(sqlModelVO.getProp() + " " + sqlModelVO.getOperation() + " " + "'" + sqlModelVO.getValues() + "'");
				_strBuffer.append(" and ");
			}
		}
		if (_strBuffer.length() > 4) {
			_strBuffer.delete(_strBuffer.length() - 4, _strBuffer.length());
		}
		return _strBuffer;
	}
	
	/**
	 * 从 配置的权限项中取出相关的配置项并生成相关的SQL
	 * @param inputNamespaceStatementId
	 * 	命名空间 形如：
	 *            com.alexgaoyh.MutiModule.Dubbo.RWSeperate.persist.manager.demo
	 *            .upload.DemoAttachmentMapper
	 * @param inputSqlStr
	 * 	执行SQL 语句
	 * @return
	 */
	private StringBuffer deployOperationListSQL(String inputNamespaceStatementId, StringBuffer inputSqlStr) {
		inputSqlStr.insert(0, "select myOperation.* from ( ").append(" ) myOperation where") ;
		
		
		List<SqlModelVO> sqlModelVOList = ConstantsSQLModelUtil.operationMap.get(inputNamespaceStatementId);
		StringBuffer _strBuffer = new StringBuffer();
		if (sqlModelVOList != null && sqlModelVOList.size() > 0) {
			for (SqlModelVO sqlModelVO : sqlModelVOList) {
				_strBuffer
						.append( " myOperation." + sqlModelVO.getAliasTabelName() + "_" + sqlModelVO.getProp() + " " + sqlModelVO.getOperation() + " " + "'" + sqlModelVO.getValues() + "'");
				_strBuffer.append(" and ");
			}
		}
		if (_strBuffer.length() > 4) {
			_strBuffer.delete(_strBuffer.length() - 4, _strBuffer.length());
		}
		inputSqlStr.append(_strBuffer);
		
		return  inputSqlStr;
	}

	@Override
	public Object plugin(Object target) {
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}
	}

	@Override
	public void setProperties(Properties properties) {

	}

}
